package com.firexxx.vp.domain.vp;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.firexxx.common.utils.UUIDUtil;
import com.firexxx.vp.domain.vp.single.mlvdata.MlvModelData;
import com.firexxx.vp.domain.vp.single.mlvdata.MlvParseModelInfo;
import com.firexxx.vp.utils.MatrixUtil;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.linear.RealMatrix;

import javax.persistence.*;
import javax.validation.constraints.NotNull;

/**
 * @description: TODO
 * @throws:
 * @author: zhuangzhang2
 * @date: 2019/12/19 10:02
 */
@Embeddable
@Getter
@NoArgsConstructor
public class VoicePrintModel {

    private final static RealMatrix lppModelWeightMatrix = MatrixUtil.getLppMatrix(
            Thread.currentThread().getContextClassLoader().getResource("models/lpp_ivector_200_200_20181009").getPath(),
            200, 200, "utf-8");

    @NotNull
    @Column(name = "vp_id")
    private String vpId;

    @NotNull
    @Column(name = "vp_model_encrypted", columnDefinition ="TEXT")
    private String vpModelEncrypted;

    @Transient
    @JsonIgnore
    private MlvModelData mlvModelData;

    @NotNull
    @Column(name = "vp_model_version")
    @Enumerated(EnumType.STRING)
    private VoicePrintResourceType vpModelVersion;

    @Embedded
    @Setter
    private VoicePrintFeature vpFeature;

    public VoicePrintModel(VoicePrintResourceType version, String vpModelEncrypted) throws Exception {
        this.vpModelEncrypted = vpModelEncrypted;

        translate();

        vpModelVersion = version;
        vpId = UUIDUtil.strings();
    }

    public boolean valid() {
        return !StringUtils.isBlank(vpId);
    }

    public float similarity(VoicePrintModel vpModel) {
        if (vpModelVersion != vpModel.vpModelVersion) {
            return 0L;
        }

        return MatrixUtil.getCosineDistance(VoicePrintModelMatrixService.lppReduceDimension(mlvModelData, lppModelWeightMatrix),
                VoicePrintModelMatrixService.lppReduceDimension(vpModel.mlvModelData, lppModelWeightMatrix));
    }

    public void translate() throws Exception {
        if (mlvModelData == null) {
            mlvModelData = MlvParseModelInfo.parseModelInfo(vpModelEncrypted, true);
        }
    }

    public void extractFeature() {
        if (vpFeature != null && vpFeature.valid()) {
            return;
        }

        rebuildFeature();
    }

    private void rebuildFeature() {
        vpFeature = new VoicePrintFeature(vpModelVersion, mlvModelData);
    }
}